Skip to content

Conversation

@c-rhodes
Copy link
Collaborator

Splats include two poison values, but only the poison-ness of the splatted value actually matters.

Splats include two poison values, but only the poison-ness of the
splatted value actually matters.
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Oct 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 15, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Cullen Rhodes (c-rhodes)

Changes

Splats include two poison values, but only the poison-ness of the splatted value actually matters.


Full diff: https://github.com/llvm/llvm-project/pull/163570.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+5)
  • (modified) llvm/unittests/Analysis/ValueTrackingTest.cpp (+10)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9655c886f4441..b0016c36bf5da 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7678,6 +7678,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(
         return true;
     }
 
+    Value *Splat;
     if (!::canCreateUndefOrPoison(Opr, Kind,
                                   /*ConsiderFlagsAndMetadata=*/true)) {
       if (const auto *PN = dyn_cast<PHINode>(V)) {
@@ -7695,6 +7696,10 @@ static bool isGuaranteedNotToBeUndefOrPoison(
         }
         if (IsWellDefined)
           return true;
+      } else if (isa<ShuffleVectorInst>(Opr) && (Splat = getSplatValue(Opr))) {
+        // For splats we only need to check the value being splatted.
+        if (OpCheck(Splat))
+          return true;
       } else if (all_of(Opr->operands(), OpCheck))
         return true;
     }
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 559a0b724f383..bb0280ee69cfd 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1091,6 +1091,16 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) {
   }
 }
 
+TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_splat) {
+  parseAssembly(
+      "define <4 x i32> @test(i32 noundef %x) {\n"
+      "  %ins = insertelement <4 x i32> poison, i32 %x, i32 0\n"
+      "  %A = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer\n"
+      "  ret <4 x i32> %A\n"
+      "}");
+  EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A));
+}
+
 TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_assume) {
   parseAssembly("declare i1 @f_i1()\n"
                 "declare i32 @f_i32()\n"

@github-actions
Copy link

github-actions bot commented Oct 15, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions c,cpp -- clang/test/CodeGen/arm-mve-intrinsics/dup.c clang/test/Headers/wasm.c llvm/lib/Analysis/ValueTracking.cpp llvm/unittests/Analysis/ValueTrackingTest.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index bb0280ee6..2c22a7a99 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1092,12 +1092,12 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) {
 }
 
 TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_splat) {
-  parseAssembly(
-      "define <4 x i32> @test(i32 noundef %x) {\n"
-      "  %ins = insertelement <4 x i32> poison, i32 %x, i32 0\n"
-      "  %A = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer\n"
-      "  ret <4 x i32> %A\n"
-      "}");
+  parseAssembly("define <4 x i32> @test(i32 noundef %x) {\n"
+                "  %ins = insertelement <4 x i32> poison, i32 %x, i32 0\n"
+                "  %A = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x "
+                "i32> zeroinitializer\n"
+                "  ret <4 x i32> %A\n"
+                "}");
   EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A));
 }
 

Copy link
Contributor

@david-arm david-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! Seems like a sensible change.

@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Oct 15, 2025
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Perhaps we can also teach this function with single-source shufflevectors.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there are two clang tests that need to be updated as well.

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Oct 16, 2025
}
if (IsWellDefined)
return true;
} else if (auto *Splat = isa<ShuffleVectorInst>(Opr) ? getSplatValue(Opr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious about how auto actually works here when selecting between two possibilities? It could choose nullptr, in which case it might be void * I presume? I can only assume it creates the type based on the first option, i.e. getSplatValue. I just wasn't sure whether the code compiles because of luck or an actual C++ specification based on ordering.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The precise rules for determining the result type of a ternary operator are exceedingly complicated, but the tl;dr is that nullptr is of type nullptr_t, which implicitly converts to all pointer types, and that's what makes this work.

@c-rhodes c-rhodes merged commit 5b5eacc into llvm:main Oct 20, 2025
9 of 10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 20, 2025

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-sie-ubuntu-fast running on sie-linux-worker while building clang,llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/38197

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'lld :: ELF/gc-sections-linker-defined-symbol.s' FAILED ********************
Exit Code: 250

Command Output (stdout):
--
# RUN: at line 3
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/llvm-mc -filetype=obj -triple=x86_64-pc-linux /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/lld/test/ELF/gc-sections-linker-defined-symbol.s -o /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.o
# executed command: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/llvm-mc -filetype=obj -triple=x86_64-pc-linux /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/lld/test/ELF/gc-sections-linker-defined-symbol.s -o /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.o
# note: command had no output on stdout or stderr
# RUN: at line 4
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/ld.lld /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.o -o /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.so --gc-sections -shared
# executed command: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/ld.lld /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.o -o /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/lld/test/ELF/Output/gc-sections-linker-defined-symbol.s.tmp.so --gc-sections -shared
# .---command stderr------------
# | terminate called after throwing an instance of 'std::system_error'
# |   what():  Resource temporarily unavailable
# `-----------------------------
# error: command failed with exit status: 250

--

********************


Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
…lvm#163570)

Splats include two poison values, but only the poison-ness of the
splatted value actually matters.
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…lvm#163570)

Splats include two poison values, but only the poison-ness of the
splatted value actually matters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants